﻿using Hx.ADSyncPlatform.ActiveDirectory;
using Hx.ADSyncPlatform.ActiveDirectory.Model;
using Hx.ADSyncPlatform.Common.Excel;
using Hx.ADSyncPlatform.Common.ExportExcel;
using Hx.ADSyncPlatform.Common.ExportExecl;
using Hx.ADSyncPlatform.Common.Log;
using Hx.ADSyncPlatform.Controllers.Base;
using Hx.ADSyncPlatform.Infrastructure.Exceptions;
using Hx.ADSyncPlatform.Infrastructure.Page;
using Hx.ADSyncPlatform.Service;
using Hx.ADSyncPlatform.WebApi.Model;
using Hx.ADSyncPlatform.WebApi.Rpc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Hx.ADSyncPlatform.Controllers
{
    /// <summary>
    /// 计算机控制器
    /// </summary>
    [Route("api/ad/computer")]
    [ApiController]
    [Authorize]
    public class ComputerController : BaseController
    {
        private ActiveDirectoryClient activeDirectoryClient;

        private SystemConfig systemConfig;

        private Plat_DataPermissionService plat_DataPermissionService;

        private RpcConfig rpcConfig;

        private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

        /// <summary>
        /// 
        /// </summary>
        /// <param name="serviceProvider"></param>
        /// <param name="activeDirectoryClient"></param>
        public ComputerController(IOptions<SystemConfig> myOptionsAccessor,
            IOptions<RpcConfig> rpcConfigAccessor,
            Plat_DataPermissionService plat_DataPermissionService,
            IServiceProvider serviceProvider, ActiveDirectoryClient activeDirectoryClient) : base(serviceProvider)
        {
            this.activeDirectoryClient = activeDirectoryClient;
            this.systemConfig = myOptionsAccessor.Value;
            this.rpcConfig = rpcConfigAccessor.Value;
            this.plat_DataPermissionService = plat_DataPermissionService;
            this.activeDirectoryClient.Computers.filterObjectByDataPermission = plat_DataPermissionService.FilterObjectHandler;
            this.activeDirectoryClient.BeforeCreatePrivateComputer = InvokeRpcSyncComputer;
        }




        #region 计算机管理（管理员）

        /// <summary>
        ///  计算机列表 分页
        /// </summary>
        /// <param name="cn">组织</param>
        /// <param name="name">计算机名</param>
        /// <param name="pagination">分页</param>
        /// <returns></returns>
        //[HttpGet("pageList")]
        //public async Task<Result<PageResult<Computer>>> PageList(string cn, string name, [FromQuery] Pagination pagination)
        //{
        //    PageResult<Computer> computers = activeDirectoryClient.Computers.PageList(cn, name, null, pagination.pageNum, pagination.pageSize);

        //    return await base.Success<PageResult<Computer>>(computers);

        //}
        //[Authorize(policy: "admin")]
        /// <summary>
        /// 管理员 绑定私人计算机 绑定到创建计算机时的用户身上
        /// </summary>
        /// <param name="samAccountName"></param>
        /// <returns></returns>
        [HttpPost("bindPersonalComputer")]
        public async Task<Result<bool>> Bind(string samAccountName)
        {
            if (string.IsNullOrWhiteSpace(samAccountName))
            {
                throw new BizException("计算机名错误！");
            }
            Computer computer = activeDirectoryClient.Computers.Single(samAccountName);
            if (computer == null) throw new BizException($"计算机【{samAccountName}】已不存在，请刷新后重试");

            if (string.IsNullOrWhiteSpace(computer.Info)) throw new BizException($"计算机【{samAccountName}】未找到拥有者，请刷新后重试");

            Person adPerson = activeDirectoryClient.Persons.Single(computer.Info);
            if (adPerson == null) throw new BizException($"计算机【{samAccountName}】拥有者【{samAccountName}】已不存在，无法绑定");

            string workStations = adPerson.UserWorkstations;

            List<string> computers = new List<string>();
            if (!string.IsNullOrWhiteSpace(adPerson.UserWorkstations)) computers = adPerson.UserWorkstations.Split(",").ToList();

            string unbindComputerName = samAccountName.Replace("$", "").ToLower();
            computers.Add(unbindComputerName);
            computers = computers.Distinct().ToList();
            adPerson.UserWorkstations = string.Join(",", computers);
            this.InvokeRpcSyncComputer(adPerson.SamAccountName, computers);
            activeDirectoryClient.Persons.Update(adPerson);
            return await base.Success<bool>(true);


        }

        //[Authorize(policy: "admin")]
        /// <summary>
        /// 管理员 绑定计算机 
        /// </summary>
        /// <returns></returns>
        [HttpPost("unbindComputer")]
        public async Task<Result<bool>> UnBind(string samAccountName, string computerType = "personal")
        {
            if (string.IsNullOrWhiteSpace(samAccountName))
            {
                throw new BizException("计算机名错误！");
            }

            Computer computer = activeDirectoryClient.Computers.Single(samAccountName);
            if (computer == null) throw new BizException($"计算机【{samAccountName}】已不存在，请刷新后重试");

            if (string.IsNullOrWhiteSpace(computer.Info)) throw new BizException($"计算机【{samAccountName}】未找到拥有者，无须解绑");

            switch (computerType)
            {
                case "personal": //私有计算机 需要清空计算机的info属性
                    {
                        Person adPerson = activeDirectoryClient.Persons.Single(computer.Info);
                        if (adPerson == null) throw new BizException($"计算机【{samAccountName}】拥有者【{computer.Info}】已不存在，无法继续操作");
                        string workStations = adPerson.UserWorkstations;
                        List<string> computers = adPerson.UserWorkstations.Split(",").ToList();
                        string account = adPerson.SamAccountName;
                        account = account.Replace(".", "-");
                        if (account.Length > 12)
                        {
                            account = account.Substring(0, 12);
                        }
                        List<string> privateComputers = computers.Where(n => n.StartsWith(account)).ToList();

                        if (privateComputers.Count == 1)
                        {
                            throw new BizException("不可以解绑所有计算机，至少保留一个！");
                        }
                        string unbindComputerName = computer.ComputerName;
                        computers.Remove(unbindComputerName);
                        adPerson.UserWorkstations = string.Join(",", computers);
                        if (adPerson.UserWorkstations == "")
                        {
                            adPerson.UserWorkstations = null;
                        }
                        this.InvokeRpcSyncComputer(computer.Info, computers);
                        activeDirectoryClient.Persons.Update(adPerson);
                        break;
                    }
                case "public":
                    {
                        break;
                    }
            }
            return await base.Success<bool>(true);


        }

        /// <summary>
        /// 个人计算机分页列表
        /// </summary>
        /// <param name="cn">当前cn</param>
        /// <param name="name"></param>
        /// <param name="pagination"></param>
        /// <returns></returns>
        //[Authorize(policy: "admin")]
        [HttpGet("personalPageList")]
        public async Task<Result<PageResult<Computer>>> PersonalPageList(string dn, string name, string searchScope, [FromQuery] Pagination pagination)
        {
            List<string> systemOus = systemConfig.systemOU.Select(n => n.name).ToList();
            PageResult<Computer> pageResult = activeDirectoryClient.Computers.PageList(dn, systemConfig.personComputer, name, platManager.DataPermissions, systemOus, searchScope, pagination.pageNum, pagination.pageSize);

            pageResult.data.ForEach(
                computer =>
                {
                    //computer.isOld = this.activeDirectoryClient.IsOldComputer(computer.Name);
                    //if (computer.isOld)
                    //{
                    //    //
                    //}
                    if (!string.IsNullOrWhiteSpace(computer.Info))
                    {
                        Person person = activeDirectoryClient.Persons.Single(computer.Info);
                        if (person != null && !string.IsNullOrWhiteSpace(person.UserWorkstations))
                        {
                            computer.Binded = person.UserWorkstations.Split(",").ToList().Contains(computer.ComputerName);
                            
                        }
                    }
                });
            //pageResult.data = pageResult.data.Where(item => !(item.isOld && !item.Binded)).ToList();
            return await base.Success<PageResult<Computer>>(pageResult);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="cn">个人计算机分页列表</param>
        /// <param name="name"></param>
        /// <param name="pagination"></param>
        /// <returns></returns>
        //[Authorize(policy: "admin")]
        [HttpGet("publicPageList")]
        public async Task<Result<PageResult<Computer>>> PublicPageList(string dn, string name, string searchScope, [FromQuery] Pagination pagination)
        {
            List<string> systemOus = systemConfig.systemOU.Select(n => n.name).ToList();
            PageResult<Computer> pageResult = activeDirectoryClient.Computers.PageList(dn, systemConfig.publicComputer, name, platManager.DataPermissions, systemOus, searchScope, pagination.pageNum, pagination.pageSize);
            return await base.Success<PageResult<Computer>>(pageResult);
        }


        /// <summary>
        ///计算机信息
        /// </summary>
        /// <param name="samAccountName"></param>
        /// <returns></returns>
        [HttpGet("{samAccountName}/info")]
        public async Task<Result<Computer>> Get([FromRoute] string samAccountName)
        {
            Computer computer = activeDirectoryClient.Computers.Info(samAccountName);

            return await base.Success<Computer>(computer);

        }

        //[Authorize(policy: "admin")]
        /// <summary>
        /// 计算机管理 根据用户账号 生成私人计算机名
        /// </summary>
        /// <returns></returns>
        [HttpGet("generate")]
        public async Task<Result<string>> GeneratePersonalComputerName(string samAccountName)
        {
            Person adPerson = activeDirectoryClient.Persons.Single(samAccountName);

            var (newComputerName, personalComputerNames) = this.activeDirectoryClient.generateComputerName(adPerson);
            return await base.Success<string>(newComputerName);
        }

        //[Authorize(policy: "admin")]
        /// <summary>
        /// 计算机管理 创建私人计算机
        /// </summary>
        /// <returns></returns>
        [HttpPost("createPersonalComputer")]
        public async Task<Result> CreatePersonComputer(string samAccountName)
        {
            Person adPerson = activeDirectoryClient.Persons.Single(samAccountName);
            this.activeDirectoryClient.CreatePersonalComputer(adPerson, systemConfig.personComputer);
            //this.createPersonalComputer(adPerson);
            return await base.Success();
        }

        //[Authorize(policy: "admin")]
        /// <summary>
        /// 创建公有计算机
        /// </summary>
        /// <param name="computerName"></param>
        /// <returns></returns>
        [HttpPost("createPublicComputer")]
        public async Task<Result> CreatePublicComputer(string dn, string computerName)
        {
            //this.createPublicComputer(dn, computerName);
            this.activeDirectoryClient.CreatePublicComputer(dn, computerName, systemConfig.publicComputer);
            return await base.Success();
        }

        //[Authorize(policy: "admin")]
        /// <summary>
        /// 导出Excel
        /// </summary>
        [HttpPost("exportExcel")]
        public async Task<object> ExportComputerExcel(string dn, string name, string searchScope)
        {
            try
            {
                List<string> systemOus = systemConfig.systemOU.Select(n => n.name).ToList();
                //获取个人计算机
                List<Computer> personComputer = activeDirectoryClient.Computers.Get(dn, systemConfig.personComputer.cn, name, platManager.DataPermissions, systemOus, searchScope);
                personComputer.ForEach(
                    computer =>
                    {
                        if (!string.IsNullOrWhiteSpace(computer.Info))
                        {
                            Person person = activeDirectoryClient.Persons.Single(computer.Info);
                            if (person != null && !string.IsNullOrWhiteSpace(person.UserWorkstations))
                            {
                                computer.Binded = person.UserWorkstations.Split(",").ToList().Contains(computer.ComputerName);
                            }
                        }
                    });
                //获取公共计算机
                List<Computer> publicComputer = activeDirectoryClient.Computers.Get(dn, systemConfig.publicComputer.cn, name, platManager.DataPermissions, systemOus, searchScope);
                if ((!personComputer.Any()) && (!publicComputer.Any())) return await base.Fail("导出失败！");
                //实体映射
                List<ExportComputerModel> personComputerData = mapper.Map<List<ExportComputerModel>>(personComputer);
                List<ExportComputerBaseModel> publicComputerData = mapper.Map<List<ExportComputerBaseModel>>(publicComputer);
                TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0);
                string excelName = $"Computer{Convert.ToInt64(ts.TotalSeconds)}.xlsx";
                List<(string, List<object>)> tuples =
                new List<(string, List<object>)>();
                tuples.Add(("私人计算机", personComputerData.Select(d => (object)d).ToList()));
                tuples.Add(("公共计算机", publicComputerData.Select(d => (object)d).ToList()));
                var stream = ExcelHelper.ExportExcels(tuples);
                if (stream != null)
                {
                    return File(stream.ToArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", excelName);
                }
                return await base.Fail("导出失败！");
            }
            catch (Exception ex)
            {
                return await base.Fail(ex.Message);
            }
        }


        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="samAccountName"></param>
        /// <returns></returns>
        [HttpDelete("{samAccountName}/delete")]
        public async Task<Result> Delete(string samAccountName)
        {
            Computer computer = activeDirectoryClient.Computers.Single(samAccountName);
            if (computer == null) throw new BizException("不存在该计算机,请刷新系统界面！");
            if (!string.IsNullOrEmpty(computer.Info))//私人计算机
            {
                Person computerOwner = activeDirectoryClient.Persons.Single(computer.Info);
                if (computerOwner != null)
                {
                    if (!string.IsNullOrEmpty(computerOwner.UserWorkstations))
                    {
                        List<string> computerNames = new List<string>();  //计算机列表
                        computerNames = computerOwner.UserWorkstations.Split(",").ToList();
                        string personAccount = computerOwner.SamAccountName + "c";
                        if (personAccount.Length > 12)
                        {
                            personAccount = personAccount.Substring(0, 12);
                        }
                        computerNames.RemoveAll(n => n == personAccount);
                        computerOwner.UserWorkstations = string.Join(",", computerNames);
#if !DEBUG
                       
#endif
                        this.InvokeRpcSyncComputer(computer.Info, computerNames);
                        activeDirectoryClient.Persons.Update(computerOwner);
                    }
                }
            }
            activeDirectoryClient.Computers.Delete(samAccountName);
            return await base.Success();


        }


        /// <summary>
        /// 创建默认计算机
        /// </summary>
        /// <returns></returns>
        [HttpPost("default")]
        public Task<Result> CreateDefaultComputer()
        {
            string account = base.platManager.Name;
            Person person = this.activeDirectoryClient.Persons.Single(account);
            this.activeDirectoryClient.CreateDefaultComputer(person, systemConfig.personComputer);
            return base.Success();

        }
        #endregion




        /// <summary>
        /// 调用远程接口同步计算机
        /// </summary>
        /// <param name="account"></param>
        /// <param name="computers">计算机列表</param>
        /// <returns></returns>
        private void InvokeRpcSyncComputer(string account, List<string> computers)
        {
            LogHelper.Default.Info("【account】:" + account);
            LogHelper.Default.Info("【InvokeRpcSyncComputer-computers】:" + Newtonsoft.Json.JsonConvert.SerializeObject(computers));
            RpcClient rpcClient = new RpcClient(this.rpcConfig);
            List<string> otherComputers = activeDirectoryClient.GetOtherComputers(account, computers);
            string otherComputersStr = "";
            if (otherComputers != null)
            {
                otherComputersStr = string.Join(",", otherComputers);
            }
            LogHelper.Default.Info("【otherComputersStr】:" + otherComputersStr);
            RpcResponse response = rpcClient.SyncComputer(account, otherComputersStr);
            if (response.Code != "200")
            {
                throw new Exception(response.Msg);
                //logHelper.ExceptionToDb(response.Msg);
                //return false;
            }
        }

    }
}
